# Copyright 2009 Mithun Chaubey 
# 
# Licensed under the Apache License, Version 2.0 (the "License"); you 
# may not use this file except in compliance with the License. You may 
# obtain a copy of the License at 
# 
#     http://www.apache.org/licenses/LICENSE-2.0
#     
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing  permissions and
# limitations under the License.

''' Module for Living History timelines '''

from google.appengine.ext import db
import wiki
import event

class timeline(wiki.entry):
    ''' Class for a timeline entry '''
    name = db.StringProperty()
    name_lcase = db.StringProperty()
    
    def put(self):
        '''
        Save timeline entry in the datastore
        @precondition: Timeline entry has a name
        @precondition: Timeline by entry name doesn't already exist in datastore
        '''
        if self.name == None:
            raise ValueError, 'Timeline name not defined'
        if self.name == "":
            raise ValueError, 'Timeline name not defined'
        
        if timeline_exists_by_name(self.name):
            raise ValueError, 'Timeline by that name exists'
        
        self.name_lcase = self.name.lower()
        
        super(timeline, self).put()
        
class timeline_revision(wiki.revision):
    ''' A revision to any timeline '''
    description = db.StringProperty()
    
    def copy(self):
        '''
        Provides a copy of this revision
        @rtype: timeline_revision
        '''
        new_rev = timeline_revision()
        new_rev.description = self.description
        return new_rev
    
    def events(self):
        '''
        All events in this revision
        @return: list[timeline_revision]
        '''
        
        ev_revs = super(timeline_revision, self).revisions_linked_to(event.event_revision)
        evs = []
        for ev_rev in ev_revs:
            evs.append(ev_rev.entry)
            
        return evs
    
    def last_event(self):
        '''
        The last event, chronologically, in this timeline revision
        @return: event
        '''
        evs = self.events()
        latest = evs[0]
        if evs[0].durationEvent:
            latest_date = evs[0].end
        else:
            latest_date = evs[0].start
            
        for ev in evs:
            if ev.durationEvent:
                if ev.end > latest_date:
                    latest = ev
                    latest_date = ev.end
            else:
                if ev.start > latest_date:
                    latest = ev
                    latest_date = ev.start
                    
        return latest
    
    def first_event(self):
        '''
        The first event, chronologically, in this timeline revision
        @return event
        '''
        evs = self.events()
        earliest = evs[0]
        for ev in evs:
            if ev.start < earliest.start:
                earliest = ev
                
        return earliest

def create_new_timeline(name, user, description):
    '''
    Create a new timeline and put it in the datastore
    
    @param name: The name of the new timeline
    @param user: The user who created the timeline
    @param description: The timeline description
    
    @type name: String
    @type user: lh_user
    @type description: String
    '''
    
    # Create new timeline
    tl = timeline()
    tl.name = name
    tl.creator = user
    tl.put()

    # Create initial revision
    tl_rev = timeline_revision()
    tl_rev.description = description
    try:
        tl_rev = tl.new_revision(tl_rev, 'Initial version', user)
    except:
        if tl_rev:
            if tl_rev.is_saved():
                tl_rev.delete()
        if tl.is_saved():
            tl.delete()
        raise
    return tl

def timeline_exists_by_name(name):
    '''
    Indicates whether timeline exists in datastore
    @param name: The name of the timeline
    @type name: String
    '''
    try:
        links = db.GqlQuery("SELECT * FROM timeline WHERE class='timeline' AND name_lcase = :1 LIMIT 1", name.lower())
    except db.KindError:
        return False

    link = links.get()
    if link:
        return True
    else:
        return False        

def get_timeline_by_name(name):
    '''
    Return timeline by name
    @param name: The timeline.name value for a timeline in the datastore
    @type name: String
    @rtype: timeline
    '''
    timelines = timeline.gql("WHERE name_lcase = :1 ORDER BY date DESC LIMIT 1", name.lower())    
    tl = timelines.get()
    
    return tl

def get_timeline_by_key_str(key_str):
    '''
    Return timeline by key string
    @param key_str: The key string of the timeline in the datastore
    @type key_str: String
    '''
    tl = db.get(db.Key(key_str))
    if not isinstance(tl, timeline):
        raise ValueError, 'Key does not refer to timeline: ' + key_str
    return tl

def get_timeline_revision_by_key_str(key_str):
    '''
    Return timeline revision by key string
    @param key_str: The key string of the revision in the datastore
    @type key_str: String
    '''
    key = db.Key(key_str)
    tl_rev = db.get(key)
    if not tl_rev:
        raise ValueError, 'Object does not exist: ' + key_str
    if not isinstance(tl_rev, timeline_revision):
        raise ValueError, 'key does not belong to timeline revision: ' + key_str
    return tl_rev
    